package com.example.wlzz.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.wlzz.config.BeansUtil;
import com.example.wlzz.constant.RedisConstant;
import com.example.wlzz.dto.WechatDTO;
import com.example.wlzz.entity.UserInfo;
import com.example.wlzz.entity.User_;
import com.example.wlzz.entity.mongoEntity.LoveNotice;
import com.example.wlzz.entity.mongoEntity.Related;
import com.example.wlzz.entity.mongoEntity.TaskNoticeStatusMsg;
import com.example.wlzz.enums.MessageEnum;
import com.example.wlzz.enums.ResultEnum;
import com.example.wlzz.repository.mongoRepository.LoveNoticeRepository;
import com.example.wlzz.repository.mongoRepository.RelatedRepository;
import com.example.wlzz.repository.mongoRepository.TaskNoticeStatusMsgRepository;
import com.example.wlzz.utils.ResultVOUtil;
import com.example.wlzz.utils.WebSocketResultVOUtil;
import com.mongodb.Block;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
/**
 * Created by yhn on 2018/8/2.
 */
@Component
@ServerEndpoint("/websocket/{token}")
@Slf4j
public class Websocket {
    //其实不是不能注入，是已经注入了，但是客户端每建立一个链接就会创建一个对象，这个对象没有任何的bean注入操作
//    @Autowired
//    private StringRedisTemplate redisTemplate;
    private Session session;
    private static CopyOnWriteArraySet<Websocket> webSocketSet = new CopyOnWriteArraySet<>();
    private int userid;   //用户的userid
    @OnOpen
    public void onOpen(@PathParam("token") String token, Session session) {
        log.warn("【websocket】token={}", token);
        //去redis查询
        StringRedisTemplate redisTemplate = BeansUtil.getBean(StringRedisTemplate.class);
        UserService userService = BeansUtil.getBean(UserService.class);
        this.session = session;
        String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.LOGIN_SUCCESS_TOKEN, token));
        User_ user = userService.findByPhone(tokenValue);
        try {
            if (StringUtils.isEmpty(tokenValue)) {  //查询redis
                log.error("【websocket】Redis中查不到token");
                session.getBasicRemote().sendText(
                        JSON.toJSONString(WebSocketResultVOUtil.error(ResultEnum.NO_LOGIN.getCode(), ResultEnum.NO_LOGIN.getMessage(),MessageEnum.FAIL.getCode())));
            } else {
                this.userid = user.getUserId();
                for (Websocket webSocket : webSocketSet) {
                    if (webSocket.userid == this.userid) {  //逼退其他相同连接下线
                        String str = JSON.toJSONString(WebSocketResultVOUtil.error(ResultEnum.ONLINE_REPEAT.getCode(),ResultEnum.ONLINE_REPEAT.getMessage(), MessageEnum.FAIL.getCode()));
                        webSocket.session.getBasicRemote().sendText(str);
                        webSocketSet.remove(webSocket);
                    }
                }
                webSocketSet.add(this);  //加入该对象
                log.info("【websocket消息】有新的连接, 总数:{}", webSocketSet.size());
                String str  = JSON.toJSONString(WebSocketResultVOUtil.success(MessageEnum.SUCCESS.getCode()));
                session.getBasicRemote().sendText(str);  //发送连接成功。
                //一旦连接成功就开始查询是否留有未通知信息。
                RelatedRepository relatedRepository = BeansUtil.getBean(RelatedRepository.class);
                //查询是否未得到的通知---->回复评论
                List<Related> relatedList =  relatedRepository.findByToUseridAndStatus(user.getUserId(),0);
                if(relatedList.size()>0){
                    session.getBasicRemote().sendText
                            (JSONObject.toJSONString(WebSocketResultVOUtil.success(relatedList,MessageEnum.REPLYCOMMENT.getCode())));  //发送信息。
                    for (Related related : relatedList) {
                        related.setStatus(1);//设置为已读
                    }
                    relatedRepository.saveAll(relatedList);
                }
                //查询点赞通知
                LoveNoticeRepository loveNoticeRepository = BeansUtil.getBean(LoveNoticeRepository.class);
                List<LoveNotice> loveNoticeList = loveNoticeRepository.findByToUseridAndStatus(user.getUserId(),0);
                if(loveNoticeList.size()>0){
                    session.getBasicRemote().sendText
                            (JSONObject.toJSONString(WebSocketResultVOUtil.success(loveNoticeList,MessageEnum.REPLYCOMMENT.getCode())));  //发送信息。
                    for (LoveNotice loveNotice : loveNoticeList) {
                        loveNotice.setStatus(1);//设置为已读
                    }
                    loveNoticeRepository.saveAll(loveNoticeList);
                }

                //查询任务状态改变的通知
                TaskNoticeStatusMsgRepository taskNoticeStatusMsgRepository = BeansUtil.getBean(TaskNoticeStatusMsgRepository.class);
                List<TaskNoticeStatusMsg> taskNoticeStatusMsgList = taskNoticeStatusMsgRepository.findByToUseridAndStatus(user.getUserId(),0);
                if(taskNoticeStatusMsgList.size()>0){
                    session.getBasicRemote().sendText
                            (JSONObject.toJSONString(WebSocketResultVOUtil.success(taskNoticeStatusMsgList,MessageEnum.TASK_STATUS_MSG.getCode())));
                    for (TaskNoticeStatusMsg taskNoticeStatusMsg : taskNoticeStatusMsgList) {
                        taskNoticeStatusMsg.setStatus(1);
                    }
                    taskNoticeStatusMsgRepository.saveAll(taskNoticeStatusMsgList);
                }
                //记得重看一下
//                MongoTemplate mongoTemplate =  BeansUtil.getBean(MongoTemplate.class);
//                MongoCollection<org.bson.Document> wechatDTOCollection =  mongoTemplate.getCollection("wechatDTO");
//                org.bson.Document wechatDocuemnt = new org.bson.Document();
//                wechatDocuemnt.put("toUserid",String.valueOf(userid));
//                wechatDocuemnt.put("flag",1);
//                FindIterable iter =  wechatDTOCollection.find(wechatDocuemnt);
//                List<Object> list = new ArrayList<>();
//                iter.forEach(new Block<Document>() {
//                    public void apply(org.bson.Document _doc) {
//                        _doc.put("flag",0);
//                        mongoTemplate.save(_doc,"wechatDTO");
//                        list.add(_doc.toJson());
//                    }
//                });
//                session.getBasicRemote().sendText
//                        (JSONObject.toJSONString(WebSocketResultVOUtil.success(list,MessageEnum.CHAT_MSG.getCode())));

            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("【websocket】建立连接：------>建立异常");
        }
    }

    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
    }
    @OnMessage
    public void onMessage(String message) {
        log.info("【websocket消息】收到客户端发来的消息:{}", message);
    }

    public void sendAllMessage(String message) {
        for (Websocket webSocket : webSocketSet) {
            log.info("【websocket消息】广播消息, message={}", message);
            try {
                webSocket.session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public String sendMessage(String message, int userid) {   //有个消息回调
        for (Websocket webSocket : webSocketSet) {
            if (webSocket.userid == userid) {  //这就说明在线了
                try {
                    webSocket.session.getBasicRemote().sendText(message);
                    return "success";  //懒得枚举了。
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }
        return null;
    }
}